// 让队列钩子依次执行，执行完毕后，执行回调 cb
function runQueue (queue, iterator, cb) {
  function next (index) {
    if (index >= queue.length) {
      return cb (); // 当队列执行完毕或空队列时执行回调,
    } else {
      let hook = queue[index];

      // 将第二个参数作为 hook 钩子的第三个参数
      // 即 hook(route, current, next)
      iterator (hook, () => next (index + 1)); // 此回调即路由钩子中的 next , 只有 在钩子中执行 next() 才会继续向下走, 队列中的钩子才会一个一个被执行，直到执行完毕执行上面的 cb
    }
  }
  next (0);
}

export default class History {
  constructor (router) {
    this.router = router;

    // 最终要将 current 变为响应式的, 变化后即更新视图
    // 路由初始化时没有匹配的记录
    this.current = creatRoute (null, {
      path: '/',
    });
  }

  // 根据路径来控制组件渲染
  transitionTo (location, onComplete) {
    console.log ('location-----', location);
    let route = this.router.match (location); // 匹配到的最新路由

    let queue = [].concat (this.router.beforeEachHooks);
    const iterator = (hook, cb) => {
      hook (route, this.current, cb); // 此时指针指向上一次匹配到的路由
    };

    //
    runQueue (queue, iterator, () => {
      this.current = route; // 路由指针更新
      this.cb && this.cb (route); // 让地址栏的 url 发生变化，随后 router-view 组件会匹配渲染对应组件
      onComplete && onComplete ();
    });
  }
  listen (cb) {
    this.cb = cb;
  }
  // 两种方式都有此方法，各自实现不同
  push () {
    throw Error ('push 方法应该由 history 子类实现');
  }
  getCurrentLocation () {
    throw Error ('getCurrentLocation 方法应该由 history 子类实现');
  }
}

/**
 * 
 * @param {*} record  从映射表中匹配到的记录
 * @param {*} location 
 */

export function creatRoute (record, location) {
  let matched = [];
  if (record) {
    // 多级路由需要都添加到 matched 中, 上一层级的排在前,下一层级的排在后
    while (record) {
      matched.unshift (record);
      record = record.parent;
    }
  }
  return {
    ...location,
    matched,
  };
}
